package com.accesshollywood.GL;

import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glOrtho;

import javax.swing.JFrame;

import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.util.vector.Vector3f;

public class MatchUpGLMain {
	public static MatchUpGLMain	matchUpGLMain;
	public MasterControl		masterControl;
	public static int			SCREEN_WIDTH	= 1920;
	public static int			SCREEN_HEIGHT	= 1080;

	public static JFrame		dummyWindow		= new JFrame();

	/** time at last frame */
	long						lastFrame;

	/** frames per second */
	int							fps;
	/** last fps time */
	long						lastFPS;

	/** is VSync Enabled */
	boolean						vsync;

	public void start() {
		try {
			Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
			Display.create();
		} catch (LWJGLException e) {
			e.printStackTrace();
			System.exit(0);
		}

		initGL(); // init OpenGL
		getDelta(); // call once before loop to initialise lastFrame
		lastFPS = getTime(); // call before loop to initialise fps timer

		initMatchUp();

		while (!Display.isCloseRequested()) {
			int delta = getDelta();
			// delta = 15;// temp for debugging
			update(delta);
			renderGL();

			Display.update();
			Display.sync(60); // cap fps to 60fps
		}

		Display.destroy();
	}

	public void initMatchUp() {
		masterControl = new MasterControl();
	}

	public void update(int delta) {
		// delta = 15; // temporary just when debugging
		masterControl.update(delta);
		updateKeyboard();
		updateMouse();
		updateFPS(); // update FPS Counter
	}

	public void updateKeyboard() {
		while (Keyboard.next()) {
			if (Keyboard.getEventKeyState()) {
				if (Keyboard.getEventKey() == Keyboard.KEY_F) {
					setDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, !Display.isFullscreen());
				} else if (Keyboard.getEventKey() == Keyboard.KEY_V) {
					vsync = !vsync;
					Display.setVSyncEnabled(vsync);
				}
			}
		}

	}

	public void updateMouse() {
		while (Mouse.next()) {
			if (Mouse.getEventButtonState()) {
				System.out.println(Mouse.getEventButton());
				Vector3f position3D = masterControl.getMousePosition(Mouse.getEventX(), Mouse.getEventY());
				AnimObject currPicked = masterControl.getClickedObj(Mouse.getEventX(), Mouse.getEventY());
				if (currPicked != null) {
					if (currPicked instanceof Match && masterControl.numSelections == 2) {
						masterControl.peopleZone.removeSelected();
					} else if (currPicked instanceof NoMatch) {
						masterControl.peopleZone.reLayout(true);
					} else if (currPicked instanceof Done) {
						masterControl.peopleZone.removeAll();
						masterControl.peopleZone.reLayout(true);
					} else {
						((Picture) currPicked).onClick();
					}
				}
				System.out.println(Mouse.getEventX() + "   " + Mouse.getEventY() + "     " + position3D.x + "   " + position3D.y + "   " + position3D.z);
				System.out.println(currPicked);
				if (masterControl.peopleZone.children.size() == 0) {
					System.out.println("no more kids!");
					masterControl.switchToCouples();
				}
			}
		}
	}

	/**
	 * Set the display mode to be used
	 * 
	 * @param width
	 *            The width of the display required
	 * @param height
	 *            The height of the display required
	 * @param fullscreen
	 *            True if we want fullscreen mode
	 */
	public void setDisplayMode(int width, int height, boolean fullscreen) {

		// return if requested DisplayMode is already set
		if ((Display.getDisplayMode().getWidth() == width) && (Display.getDisplayMode().getHeight() == height) && (Display.isFullscreen() == fullscreen)) {
			return;
		}

		try {
			DisplayMode targetDisplayMode = null;

			if (fullscreen) {
				DisplayMode[] modes = Display.getAvailableDisplayModes();
				int freq = 0;

				for (int i = 0; i < modes.length; i++) {
					DisplayMode current = modes[i];

					if ((current.getWidth() == width) && (current.getHeight() == height)) {
						if ((targetDisplayMode == null) || (current.getFrequency() >= freq)) {
							if ((targetDisplayMode == null) || (current.getBitsPerPixel() > targetDisplayMode.getBitsPerPixel())) {
								targetDisplayMode = current;
								freq = targetDisplayMode.getFrequency();
							}
						}

						// if we've found a match for bpp and frequence against
						// the
						// original display mode then it's probably best to go
						// for this one
						// since it's most likely compatible with the monitor
						if ((current.getBitsPerPixel() == Display.getDesktopDisplayMode().getBitsPerPixel()) && (current.getFrequency() == Display.getDesktopDisplayMode().getFrequency())) {
							targetDisplayMode = current;
							break;
						}
					}
				}
			} else {
				targetDisplayMode = new DisplayMode(width, height);
			}

			if (targetDisplayMode == null) {
				System.out.println("Failed to find value mode: " + width + "x" + height + " fs=" + fullscreen);
				return;
			}

			Display.setDisplayMode(targetDisplayMode);
			Display.setFullscreen(fullscreen);

		} catch (LWJGLException e) {
			System.out.println("Unable to setup mode " + width + "x" + height + " fullscreen=" + fullscreen + e);
		}
	}

	/**
	 * Calculate how many milliseconds have passed since last frame.
	 * 
	 * @return milliseconds passed since last frame
	 */
	public int getDelta() {
		long time = getTime();
		int delta = (int) (time - lastFrame);
		lastFrame = time;

		return delta;
	}

	/**
	 * Get the accurate system time
	 * 
	 * @return The system time in milliseconds
	 */
	public long getTime() {
		return (Sys.getTime() * 1000) / Sys.getTimerResolution();
	}

	/**
	 * Calculate the FPS and set it in the title bar
	 */
	public void updateFPS() {
		if (getTime() - lastFPS > 1000) {
			Display.setTitle("FPS: " + fps);
			fps = 0;
			lastFPS += 1000;
		}
		fps++;
	}

	public void initGL() {
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, -1);
		glMatrixMode(GL_MODELVIEW);
	}

	public void renderGL() {
		// Clear The Screen And The Depth Buffer
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

		// R,G,B,A Set The Color To Blue One Time Only
		glColor3f(1.0f, 1.0f, 1.0f);

		masterControl.render();
	}

	public static void main(String[] argv) {
		matchUpGLMain = new MatchUpGLMain();

		matchUpGLMain.start();
	}
}
